import 'dart:convert';
import 'dart:typed_data';

import 'package:tool/rive/buffer_reader_ext.dart';
import 'package:tool/rive/field_type.dart';

import 'obj_type.dart';

class RiveObj {
  final Uint8List bytes;
  final int pos;
  late int length;

  RiveObj(this.bytes, this.pos);

  late int type;

  String get typeName => readObjTypeKey(type);

  final obj = <String, dynamic>{};

  int init() {
    var pos = this.pos;
    final typeUleb = bytes.readUleb128(pos);
    type = typeUleb.value;
    pos += typeUleb.length;

    // read property type
    while (true) {
      final keyUleb = bytes.readUleb128(pos);
      pos += keyUleb.length;
      var keyInt = keyUleb.value;
      if (keyInt == 0) {
        break;
      }

      // read property key
      final key = convertFieldTypeToClassName(keyInt);

      // value type
      final valueType = convertFieldTypeToEnum(keyInt);

      switch (valueType) {
        case CoreFieldType.boolType:
          final value = bytes[pos] == 1;
          obj[key] = value;
          pos += 1;
          break;
        case CoreFieldType.uintType:
          final varInt = bytes.readUleb128(pos);
          obj[key] = varInt.value;
          pos += varInt.length;
          break;
        case CoreFieldType.doubleType:
          final value =
              bytes.buffer.asByteData().getFloat32(pos, Endian.little);
          obj[key] = value;
          pos += 4;
          break;
        case CoreFieldType.stringType:
          final length = bytes.readUleb128(pos);
          pos += length.length;
          final buffer = bytes.sublist(pos, pos + length.value);
          obj[key] = utf8.decode(buffer);
          pos += length.value;
          break;
        case CoreFieldType.colorType:
          final value = bytes.buffer.asByteData().getUint32(pos, Endian.little);
          // Color to hex string
          final hex = value.toRadixString(16).padLeft(8, '0').toUpperCase();
          obj[key] = 'color: $hex';
          pos += 4;
          break;
        case CoreFieldType.bytesType:
          final length = bytes.readUleb128(pos);
          pos += length.length;
          final buffer = bytes.sublist(pos, pos + length.value);
          obj[key] = buffer;
          break;
        default:
          throw Exception(
              'unknown value type: $valueType, the key: $key, the keyInt: $keyInt, typeName: $typeName, pos: ${hex(pos)}');
      }
    }

    length = pos - this.pos;
    return length;
  }

  String hex(int value) {
    return '0x${value.toRadixString(16).padLeft(8, '0').toUpperCase()}';
  }

  String debugString([int index = 0]) {
    final properties =
        obj.entries.map((e) => '    ${e.key}: ${e.value}').join('\n');

    return 'object $index:\n  $typeName\n$properties';
  }
}
